import { fabric } from 'fabric';
// import { throttle } from 'lodash';
import DrawLine from './DrawLine';
// import initRuler from './ruler';
// import CanvasRuler from './ruler/ruler';
import ControlsPlugin from './initControls';
// import initAligningGuidelines from './initAligningGuidelines';
import initGuidelines from './initGuidelines';

declare type EditorWorkspaceOption = {
    workspaceId?: string;
    mode?: string;
};
declare type ExtCanvas = fabric.Canvas & {
    isDragging: boolean;
    lastPosX: number;
    lastPosY: number;
};
export const DefaultWorkSpaceColor = 'rgba(255,255,255,1)';

class EditorWorkspace {
    canvas: fabric.Canvas;
    workspaceEl: HTMLElement;
    workspace: fabric.Rect | null;
    option: EditorWorkspaceOption;
    dragMode: boolean;
    fill: string;
    width: number | undefined;
    height: number | undefined;
    scale: number | undefined;
    drawLine: DrawLine;
    // drawShape: DrawShape;
    // ruler: CanvasRuler;
    mainImg: fabric.Image | null = null;
    mode: string | undefined;
    // disableGuidelines: () => void;
    // enableGuidelines: () => void;

    constructor(canvas: fabric.Canvas, option: EditorWorkspaceOption) {
        this.canvas = canvas;
        if (option.workspaceId) {
            this.workspaceEl = document.querySelector(option.workspaceId) as HTMLElement;
        } else {
            this.workspaceEl = this.canvas.getElement();
        }
        this.workspace = null;
        this.mode = option.mode;
        this.option = option;
        this.dragMode = false;
        this.fill = DefaultWorkSpaceColor;
        this.drawLine = new DrawLine(canvas, this);
        // initGuidelines(canvas);
        // this.drawShape = new DrawShape(canvas, this);
        // this.ruler = initRuler(canvas);
        // const { disable, enable } = initAligningGuidelines(canvas);
        // this.disableGuidelines = disable;
        // this.enableGuidelines = enable;
        new ControlsPlugin(canvas);
        this.initBackground();
        this.initResizeObserve();
        this.addEventListener();
        // this.initDring();
    }

    // 初始化背景
    initBackground() {
        this.width = this.workspaceEl.offsetWidth;
        this.height = this.workspaceEl.offsetHeight;
        this.canvas.setWidth(this.workspaceEl.offsetWidth);
        this.canvas.setHeight(this.workspaceEl.offsetHeight);
    }

    // 替换画布数据
    echoTemplate(json: any) {
        if (json.version) {
            return this.handleNewData(json);
        }
        return this.handleOldData(json);
    }

    // 处理新数据
    handleNewData(json: any) {
        if (!json.objects || !json.objects.length) return Promise.resolve();
        return new Promise((resolve, reject) => {
            const src = json.objects.find((item: { id: string }) => item.id === 'mainImg')?.src;
            const image = new Image();
            image.src = src;
            image.crossOrigin = 'anonymous';
            image.onload = () => {
                this.canvas.loadFromJSON(json, () => {
                    const objects = this.canvas.getObjects();
                    objects.forEach((item: any) => {
                        if (item.id === 'workspace') {
                            this.workspace = item;
                        } else if (item.id === 'mainImg') {
                            this.mainImg = item;
                        }
                    });
                    if (this.workspace) {
                        this.setSize(this.workspace.width as number, this.workspace.height as number);
                    }
                    this.toViewCanvas();
                    resolve(true);
                });
            };
            image.onerror = (err) => {
                reject(err);
                alert('摊位图纸加载失败，请刷新页面重试');
            };
        });
    }

    // 处理旧数据
    handleOldData(json: any) {
        if (!json || !json.info || !json.info.data.length) return Promise.resolve();
        return new Promise((resolve, reject) => {
            const {
                info: { data, imageByte },
            } = json;
            const binary = atob(imageByte);
            const array = [];
            for (let i = 0; i < binary.length; i++) {
                array.push(binary.charCodeAt(i));
            }
            const blob = new Blob([new Uint8Array(array)], { type: 'image/jpeg' });

            // 创建一个可以被Fabric识别的URL
            const url = URL.createObjectURL(blob);

            this.initRect(url)
                .then(() => {
                    data.forEach((item: any) => {
                        const POLYPOINTarr = item.POLYPOINT.split(',');
                        const points: any = POLYPOINTarr.map((point: string, index: number) => {
                            if (index % 2 === 0) {
                                return {
                                    x: parseInt(point),
                                    y: parseInt(POLYPOINTarr[index + 1]),
                                };
                            }
                        }).filter((x: any) => x);
                        const polygon = new fabric.Polygon(points, {
                            fill: item.GHPLCOLOR,
                        });
                        const group = this.drawShape.createBoothGroup(polygon, {
                            boothClass: item.GHPLMC,
                            boothCode: item.SHOPDM,
                            boothArea: `${item.JYMJ}㎡`,
                        });
                        this.canvas.add(group);
                    });
                    this.toViewCanvas();
                    resolve(true);
                })
                .catch(reject);
        });
    }

    // rect and image
    initRect(src: string) {
        return new Promise((resolve, reject) => {
            fabric.Image.fromURL(
                src,
                (img: fabric.Image) => {
                    if (!img || !img.width || !img.height) {
                        reject(null);
                        return alert('摊位图纸加载失败，请刷新页面重试');
                    }
                    this.canvas.discardActiveObject();
                    this.clearAllObject();
                    img.set({
                        type: 'image',
                        left: 0,
                        top: 0,
                        id: 'mainImg',
                        selectable: false,
                        hasControls: false,
                        hoverCursor: 'default',
                    });
                    this.width = img.width;
                    this.height = img.height;
                    const workspace = new fabric.Rect({
                        fill: this.fill,
                        width: this.width,
                        height: this.height,
                        id: 'workspace',
                        selectable: false,
                        hasBorders: false,
                        hoverCursor: 'default',
                    });
                    this.mainImg = img;
                    this.workspace = workspace;
                    this.canvas.add(workspace);
                    this.canvas.add(img);
                    this.canvas.renderAll();
                    this.auto();
                    resolve(true);
                },
                { crossOrigin: 'anonymous' }
            );
        });
    }
    /**
     * 设置画布中心到指定对象中心点上
     * @param {Object} obj 指定的对象
     */
    setCenterFromObject(obj: fabric.Rect) {
        const { canvas } = this;
        const objCenter = obj.getCenterPoint();
        const viewportTransform = canvas.viewportTransform;
        if (canvas.width === undefined || canvas.height === undefined || !viewportTransform) return;
        viewportTransform[4] = canvas.width / 2 - CalcWidth - objCenter.x * viewportTransform[0];
        viewportTransform[5] = canvas.height / 2 - objCenter.y * viewportTransform[3];
        canvas.setViewportTransform(viewportTransform);
        canvas.renderAll();
    }

    // 初始化监听器
    initResizeObserve() {
        // const resizeObserver = new ResizeObserver(
        //     throttle(() => {
        //         this.auto();
        //     }, 50)
        // );
        // resizeObserver.observe(this.workspaceEl);
    }

    isNumber = (value: string | number) => {
        return typeof value === 'number';
    };

    setSize(width: number | string, height: number | string) {
        this.initBackground();
        this.width = (this.isNumber(width) ? width : +width) as number;
        this.height = (this.isNumber(height) ? height : +height) as number;
        // 重新设置workspace
        this.workspace = this.canvas.getObjects().find((item) => item.id === 'workspace') as fabric.Rect;
        this.workspace.set('width', this.width);
        this.workspace.set('height', this.height);
        this.auto();
    }

    setZoomAuto(scale: number, cb?: (left?: number, top?: number) => void) {
        const { workspaceEl } = this;
        const width = workspaceEl.offsetWidth;
        const height = workspaceEl.offsetHeight;
        this.canvas.setWidth(width);
        this.canvas.setHeight(height);
        const center = this.canvas.getCenter();
        this.canvas.setViewportTransform(fabric.iMatrix.concat());
        this.canvas.zoomToPoint(new fabric.Point(center.left, center.top), scale);
        if (!this.workspace) return;
        this.setCenterFromObject(this.workspace);

        // 超出画布不展示
        this.workspace.clone((cloned: fabric.Rect) => {
            this.canvas.clipPath = cloned;
            this.canvas.requestRenderAll();
        });
        if (cb) cb(this.workspace.left, this.workspace.top);
    }

    getScale() {
        const viewPortWidth = this.workspaceEl.offsetWidth;
        const viewPortHeight = this.workspaceEl.offsetHeight;
        const width = this.width || 0;
        const height = this.height || 0;
        if (!width || !height) return 0;
        // 按照宽度
        if (viewPortWidth / viewPortHeight < width / height) {
            return Number(subtract(divide(bignumber(viewPortWidth), bignumber(width)), 0.08));
        } // 按照宽度缩放
        return Number(subtract(divide(bignumber(viewPortHeight), bignumber(height)), 0.08));
    }

    // 放大
    big(value: number) {
        let zoomRatio = this.canvas.getZoom();
        zoomRatio += value || 0.05;
        if (zoomRatio >= 3) {
            zoomRatio = 3;
        }
        const center = this.canvas.getCenter();
        this.canvas.zoomToPoint(new fabric.Point(center.left, center.top), zoomRatio);
    }

    // 缩小
    small(value: number) {
        let zoomRatio = this.canvas.getZoom();
        zoomRatio -= value || 0.05;
        if (zoomRatio <= 0.1) {
            zoomRatio = 0.1;
        }
        const center = this.canvas.getCenter();
        this.canvas.zoomToPoint(new fabric.Point(center.left, center.top), zoomRatio < 0 ? 0.01 : zoomRatio);
    }

    // 自动缩放
    auto() {
        const scale = this.getScale();
        if (scale) {
            this.scale = scale;
            this.setZoomAuto(scale);
        }
    }

    // 1:1 放大
    one() {
        this.setZoomAuto(0.8 - 0.08);
        this.canvas.requestRenderAll();
    }

    addEventListener() {
        this.canvas.on('selection:created', (e) => {
            const selectedObjects = e.selected;

            if (selectedObjects?.length && selectedObjects[0].type === 'polyline') {
                // 在这里应用自定义的选中效果
                this.canvas.forEachObject((obj) =>  {
                    if (obj.type === 'circle') {
                        this.canvas.remove(obj);
                    }
                });
            }
        });

        // let scaleRatio = 1;
        this.canvas.on('mouse:wheel',  (opt) => {
            const delta = opt.e.deltaY;
            // let zoom = scaleRatio;
            // zoom *= 0.999 ** delta;

            // // 获取当前画布的所有对象
            // const objects = this.canvas.getObjects();

            // // 计算缩放比例
            // // var scaleRatio = 0.5; // 缩放比例为0.5，即将画布调整为原来的一半大小

            // // 调整每个对象的位置和大小
            // objects.forEach((object: any) => {
            //     // 调整对象的位置
            //     object.left *= zoom;
            //     object.top *= zoom;

            //     // 调整对象的大小
            //     object.scaleX *= zoom;
            //     object.scaleY *= zoom;

            //     object.strokeWidth = 1 / object.scaleY;
            // });

            // scaleRatio = zoom;

            // // 调整画布的大小
            // var newWidth = this.canvas.getWidth() * scaleRatio;
            // var newHeight = this.canvas.getHeight() * scaleRatio;
            // this.canvas.setDimensions({ width: newWidth, height: newHeight });
            let zoom = this.canvas.getZoom();
            zoom *= 0.999 ** delta;
            // if (zoom > 20) zoom = 20;
            // if (zoom < 0.1) zoom = 0.1;
            const center = this.canvas.getCenter();
            this.canvas.zoomToPoint(new fabric.Point(center.left, center.top), zoom);
            // const center = that.canvas.getPointer(opt.e);
            // this.zoomToPoint(new fabric.Point(center.x, center.y), zoom);
            opt.e.preventDefault();
            opt.e.stopPropagation();

            const objects = this.canvas.getObjects();
            // console.log(1 / zoom)

            objects.forEach((object) => {
                console.log(object)
                // object.strokeWidth = 0.01;//1 / zoom;
            });
        });

        /**
         * 滚轮缩放
         */
        // this.canvas.on('mouse:wheel',  (opt) => {
        //     const delta = opt.e.deltaY;
        //     let zoom = this.canvas.getZoom();
        //     zoom *= 0.999 ** delta;
        //     // if (zoom > 20) zoom = 20;
        //     // if (zoom < 0.1) zoom = 0.1;
        //     const center = this.canvas.getCenter();
        //     this.canvas.zoomToPoint(new fabric.Point(center.left, center.top), zoom);
        //     // const center = that.canvas.getPointer(opt.e);
        //     // this.zoomToPoint(new fabric.Point(center.x, center.y), zoom);
        //     opt.e.preventDefault();
        //     opt.e.stopPropagation();

        //     const objects = this.canvas.getObjects();
        //     console.log(1 / zoom)

        //     objects.forEach((object) => {
        //         object.strokeWidth = 0.01;//1 / zoom;
        //     });
        // });
    }

    // // 开始拖拽
    // startDring() {
    //     if (this.mainImg) {
    //         this.mainImg.set('hoverCursor', 'grab');
    //     }
    //     this.dragMode = true;
    //     this.canvas.defaultCursor = 'grab';
    //     this.canvas.renderAll();
    // }

    // endDring() {
    //     if (this.mainImg) {
    //         this.mainImg.set('hoverCursor', 'default');
    //     }
    //     // this.ruler.showGuideline();
    //     this.dragMode = false;
    //     this.canvas.defaultCursor = 'default';
    //     this.canvas.renderAll();
    // }

    // 拖拽模式
    // initDring() {
    //     // eslint-disable-next-line @typescript-eslint/no-this-alias
    //     const that = this;
    //     this.canvas.on('mouse:down', function (this: ExtCanvas, opt) {
    //         const evt = opt.e;
    //         if (evt.altKey || that.dragMode) {
    //             that.canvas.defaultCursor = 'grabbing';
    //             that.canvas.discardActiveObject();
    //             that.setDring();
    //             this.isDragging = true;
    //             this.lastPosX = evt.clientX;
    //             this.lastPosY = evt.clientY;
    //             this.requestRenderAll();
    //         }
    //     });

    //     this.canvas.on('mouse:move', function (this: ExtCanvas, opt) {
    //         if (this.isDragging) {
    //             // that.ruler.hideGuideline();
    //             that.canvas.discardActiveObject();
    //             that.canvas.defaultCursor = 'grabbing';
    //             const { e } = opt;
    //             if (!this.viewportTransform) return;
    //             const vpt = this.viewportTransform;
    //             vpt[4] += e.clientX - this.lastPosX;
    //             vpt[5] += e.clientY - this.lastPosY;
    //             this.lastPosX = e.clientX;
    //             this.lastPosY = e.clientY;
    //             this.requestRenderAll();
    //         }
    //     });

    //     this.canvas.on('mouse:up', function (this: ExtCanvas) {
    //         if (!this.viewportTransform) return;
    //         this.setViewportTransform(this.viewportTransform);
    //         this.isDragging = false;
    //         if (!that.drawLine.isDrawing) {
    //             that.getObjects().forEach((obj) => {
    //                 obj.selectable = true;
    //                 obj.lockMovementX = false;
    //                 obj.lockMovementY = false;
    //             });
    //         }
    //         that.canvas.defaultCursor = 'default';
    //         this.requestRenderAll();
    //     });

    //     // 鼠标缩放事件
    //     this.canvas.on('mouse:wheel', function (this: fabric.Canvas, opt) {
    //         const delta = opt.e.deltaY;
    //         let zoom = this.getZoom();
    //         zoom *= 0.999 ** delta;
    //         if (zoom > 20) zoom = 20;
    //         if (zoom < 0.1) zoom = 0.1;
    //         const center = this.getCenter();
    //         this.zoomToPoint(new fabric.Point(center.left, center.top), zoom);
    //         // const center = that.canvas.getPointer(opt.e);
    //         // this.zoomToPoint(new fabric.Point(center.x, center.y), zoom);
    //         opt.e.preventDefault();
    //         opt.e.stopPropagation();
    //     });
    // }

    setDring() {
        this.canvas.defaultCursor = 'grab';
        if (this.mode !== PageType.view) {
            this.getObjects().forEach((obj) => {
                obj.selectable = false;
                obj.lockMovementX = true;
                obj.lockMovementY = true;
            });
        }
        this.canvas.requestRenderAll();
    }
    // 清空全部对象
    clearAllObject() {
        this.canvas.getObjects().forEach((item: fabric.Object) => {
            this.canvas.remove(item);
        });
        return this.canvas;
    }
    // 获取json
    getJson() {
        return this.canvas.toJSON(['id', 'cType', 'selectable', 'hasControls', 'groupFill', 'hoverCursor', 'isEditPoint']);
    }
    // 获取图片
    getBase64Image() {
        const workspace = this.workspace;
        this.ruler.hideGuideline();
        if (!workspace) return;
        const { left, top, width, height } = workspace;
        const option = {
            format: 'png',
            quality: 1,
            left,
            top,
            width,
            height,
        };
        const scale = this.canvas.getZoom();
        this.canvas.setViewportTransform([1, 0, 0, 1, 0, 0]);
        const dataUrl = this.canvas.toDataURL(option);
        this.setZoomAuto(scale);
        this.ruler.showGuideline();
        return dataUrl;
    }
    getObjects() {
        return this.canvas.getObjects().filter((item) => !['workspace', 'mainImg'].includes(item.id || ''));
    }
    // 进入查看模式，只能选中不能移动和修改
    toViewCanvas() {
        if (this.mode !== PageType.view) return;
        this.canvas.discardActiveObject();
        const objects = this.getObjects();
        objects.forEach((item) => {
            item.set({
                lockMovementX: true,
                lockMovementY: true,
                hasControls: false,
                hoverCursor: 'pointer',
                selectable: true,
            });
        });
        this.canvas.renderAll();
    }
}

export default EditorWorkspace;
